package com.yida.auth.service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.yida.common.core.constant.CacheConstants;
import com.yida.common.core.constant.Constants;
import com.yida.common.core.constant.HttpStatus;
import com.yida.common.core.constant.SecurityConstants;
import com.yida.common.core.domain.R;
import com.yida.common.core.exception.ServiceException;
import com.yida.common.core.utils.StringUtils;
import com.yida.common.core.utils.regular.ReUtils;
import com.yida.common.redis.service.RedisService;
import com.yida.system.api.RemoteSmsService;
import com.yida.system.api.domain.SysSms;
import com.yida.system.api.domain.SysUser;

/**
 * 短信发送
 * 
 * @author hmh
 * @date 2022/10/26
 */
@Component
public class SysSmsService {

    // 验证码是否显示给前端
    private final String isPhoneCodeFront = "sys.phonenumber.codeFrontEnabled";

    @Autowired
    private RemoteSmsService remoteSmsService;

    @Autowired
    private SysRecordLogService recordLogService;

    @Autowired
    private RedisService redisService;

    /**
     * 发送验证码
     * 
     * @param username 用户名
     * @param phonenumber 手机号
     * @return Map<String,String>
     */
    public Map<String, Object> sendSmsCode(String username, String phonenumber) {
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(username, phonenumber)) {
            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "用户/手机号必须填写");
            throw new ServiceException("用户/手机号必须填写");
        }
        // 手机号不符合规定
        if (!ReUtils.checkPhone(phonenumber)) {
            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, "输入手机号[" + phonenumber + "]不合法");
            throw new ServiceException("输入手机号不合法");
        }
        // 从缓存中获取验证码
        String sms = redisService.getCacheObject(getSmsCacheKey(phonenumber));
        if (StringUtils.isNotEmpty(sms)) {
            throw new ServiceException("[" + phonenumber + "]两次发送间隔未超过" + CacheConstants.SMS_CODE_EXPIRATION + "分钟，请不要重复发送！");
        }
        // 发送手机验证码
        SysUser sysUser = new SysUser();
        sysUser.setUserName(username);
        sysUser.setPhonenumber(phonenumber);
        R<SysSms> sysSmsResult = remoteSmsService.sendMsgCode(sysUser, SecurityConstants.INNER);
        if (StringUtils.isNull(sysSmsResult) || StringUtils.isNull(sysSmsResult.getData())) {

            recordLogService.recordLogininfor(username, Constants.LOGIN_FAIL, sysSmsResult.getMsg());
            throw new ServiceException("登录用户：" + username + "[" + sysSmsResult.getMsg() + "]");
        }
        if (R.FAIL == sysSmsResult.getCode()) {
            throw new ServiceException(sysSmsResult.getMsg());
        }
        SysSms sysSms = sysSmsResult.getData();
        // 设置当前短信验证码有效期
        redisService.setCacheObject(getSmsCacheKey(phonenumber), sysSms.getSms(), CacheConstants.SMS_CODE_EXPIRATION, TimeUnit.MINUTES);
        // 获取显示设置
        String codeFrontEnabled = redisService.getCacheObject(getCacheKey(isPhoneCodeFront));
        if (StringUtils.isBlank(codeFrontEnabled)) {
            codeFrontEnabled = "true";
        }
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("sms", "ok");
        map.put("code", HttpStatus.SUCCESS);
        if ("true".equals(codeFrontEnabled)) {
            map.put("phonenumber", phonenumber);
            map.put("sms", sysSms.getSms());
        }
        return map;
    }

    /**
     * 验证验证码是否一致
     * 
     * @param phonenumber 手机号
     * @param smsCode 验证码
     * @return boolean
     */
    public Map<String, Object> verifySmsCode(String phonenumber, String smsCode) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("msg", "验证码过期，请重新发送！");
        map.put("code", HttpStatus.ERROR);
        // 1由缓存查询验证码
        String chceSmsCode = redisService.getCacheObject(getSmsCacheKey(phonenumber));
        if (!StringUtils.isEmpty(chceSmsCode)) {
            // 2检查验证码是否一致
            if (!chceSmsCode.equals(smsCode)) {
                map.put("smsCode", chceSmsCode);
                map.put("msg", "验证码错误，请核对！");
                return map;
            }
            map.put("msg", "ok");
            map.put("code", HttpStatus.SUCCESS);
            redisService.deleteObject(getSmsCacheKey(phonenumber));
            remoteSmsService.removeSmsCode(phonenumber, SecurityConstants.INNER);
        }
        return map;
    }

    // ******************************************新增功能项*************************************************************
    /**
     * 发送验证码
     * 
     * @param username 用户名
     * @param phonenumber 手机号
     * @return Map<String,String>
     */
    public Map<String, Object> sendSms(SysSms sysSms, String configKey) {
        String phonenumber = sysSms.getPhonenumber();
        // 用户名或密码为空 错误
        if (StringUtils.isAnyBlank(phonenumber)) {
            throw new ServiceException("手机号必须填写");
        }
        // 手机号不符合规定
        if (!ReUtils.checkPhone(phonenumber)) {
            throw new ServiceException("输入手机号[" + phonenumber + "]不合法");
        }
        // 从缓存中获取验证码
        String redisSmsKey = redisService.getCacheObject(getSmsCacheKey(configKey + ":" + phonenumber));
        if (StringUtils.isNotEmpty(redisSmsKey)) {
            throw new ServiceException("[" + phonenumber + "]两次发送间隔未超过" + CacheConstants.SMS_CODE_EXPIRATION + "分钟，请不要重复发送！");
        }
        R<SysSms> sysSmsResult = remoteSmsService.sendAuthSmsByPhonenumber(sysSms, SecurityConstants.INNER);
        if (StringUtils.isNull(sysSmsResult) || StringUtils.isNull(sysSmsResult.getData())) {
            throw new ServiceException("手机号：" + phonenumber + "短信发送失败！");
        }
        if (R.FAIL == sysSmsResult.getCode()) {
            throw new ServiceException("手机号：" + phonenumber + "[" + sysSmsResult.getMsg() + "]");
        }
        SysSms remoteSysSms = sysSmsResult.getData();
        // 设置当前短信内容有效期
        redisService.setCacheObject(getSmsCacheKey(redisSmsKey), remoteSysSms.getSms(), CacheConstants.SMS_CODE_EXPIRATION, TimeUnit.MINUTES);
        // 获取显示设置
        String codeFrontEnabled = redisService.getCacheObject(getCacheKey(isPhoneCodeFront));
        if (StringUtils.isBlank(codeFrontEnabled)) {
            codeFrontEnabled = "true";
        }
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("sms", "ok");
        if ("true".equals(codeFrontEnabled)) {
            map.put("phonenumber", phonenumber);
            map.put("sms", sysSms.getSms());
        }
        map.put("code", HttpStatus.SUCCESS);
        return map;
    }

    /**
     * 验证验证码是否一致
     * 
     * @param phonenumber 手机号
     * @param smsCode 验证码
     * @return boolean
     */
    public Map<String, Object> verifySmsCode(String phonenumber, String smsCode, String customConfigKey) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("msg", "验证码过期，请重新发送！");
        map.put("code", HttpStatus.ERROR);
        String tempConfigKey = phonenumber;
        if (StringUtils.isNotEmpty(customConfigKey)) {
            tempConfigKey = customConfigKey + ":" + phonenumber;
        }
        // 1由缓存查询验证码
        String chceSmsCode = redisService.getCacheObject(getSmsCacheKey(tempConfigKey));
        if (!StringUtils.isEmpty(chceSmsCode)) {
            // 2检查验证码是否一致
            if (!chceSmsCode.equals(smsCode)) {
                map.put("smsCode", chceSmsCode);
                map.put("msg", "验证码错误，请核对！");
                return map;
            }
            map.put("msg", "ok");
            map.put("code", HttpStatus.SUCCESS);
            redisService.deleteObject(getSmsCacheKey(tempConfigKey));
            remoteSmsService.removeSms(phonenumber, 1, customConfigKey, SecurityConstants.INNER);
        }
        return map;
    }
    // ******************************************新增功能项*************************************************************

    /**
     * 设置cache key
     * 
     * @param configKey 参数键
     * @return 缓存键key
     */
    public String getSmsCacheKey(String configKey) {
        return CacheConstants.SMS_CODE_EXPIRATION_KEY + configKey;
    }

    /**
     * 设置cache key
     * 
     * @param configKey 参数键
     * @return 缓存键key
     */
    public String getCacheKey(String configKey) {
        return CacheConstants.SYS_CONFIG_KEY + configKey;
    }
}
